package com.yyge.config;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 通知类
 * AOP
 */
@Component
@Aspect

public class MyAdvice {
    //定义切入点：切入点是一种正则表达式，用于描述要为那些方法进行增强
    //被切入点匹配的方法称为连接点
    //切入点的方法必须是private，返回之必须是void,方法不需要方法体
    //切入点表达式语法:访问修饰符(可以省略)返回值类型 包.类.方法(参数)
    //execution(* *..*(..))
    @Pointcut("execution(* com.yyge.mapper.*.selectAll(..))")
    private void pt(){};

    /**
     * 第二步:前置通知：执行目标对象方法前(连接点)执行的通知->目标对象的方法的执行
     * @param joinPoubt
     */
    /*前置通知*/@Before("pt()")
    public void before(JoinPoint joinPoubt){
       //执行连接点的方法前获取的方法实参
       Object[] args=joinPoubt.getArgs();
       //获取被执行的方法名
        Signature signature=joinPoubt.getSignature();
        String name=signature.getName();

        //通知：具有共性的方法
        System.out.println("前置通知:系统当前时间："+System.currentTimeMillis()+"\t 执行的方法:"+name+",参数列表："+ Arrays.toString(args));
    }

    @Before("execution(* com.yyge.mapper.*.insert(..))")
    public void insertBefore(){
        System.out.println("执行insert的前置通知");
    }


    /*后置通知*/@After("pt()")
    public void after(){
       System.out.println("后置通知:系统当前时间："+System.currentTimeMillis());
    }


    /**
     * 第三步：返回后通知: 当连接点有返回值的时候，执行返回后通知 -> 后置通知
     * @param result
     */
    /*返回后通知*/@AfterReturning(value = "pt()",returning = "result")
    public void  afterReturning(Object result){
        System.out.println("返回后通知：方法返回结果后执行的通知:\t\t"+result);
    }

    /**
     * 抛出异常后通知： 如果在目标方法执行过程中发生了异常，则进入 抛出异常后的通知 -> 环绕通知
     * @param t
     */
    /*抛出异常后通知*/@AfterThrowing(value = "pt()",throwing = "t")
    public void throwing(Throwable t){
        System.out.println("异常信息："+t.getMessage());
    }


    /*环绕通知*/
    @Around("pt()")
    public Object around(ProceedingJoinPoint joinPoint){
        System.out.println("环绕通知前：");
        long begin=System.currentTimeMillis();
        Object proceed= null;
        try {
            proceed=joinPoint.proceed();
        }catch (Throwable e){
            e.printStackTrace();
        }

        System.out.println("环绕通知后：");
        long end=System.currentTimeMillis();
        System.out.println("方法执行时间："+(end-begin)+"ms");
        return proceed;
    }

}
